﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Controls;

namespace BalanceManager.Model
{
    public interface IFundFlowsRepository
    {
        ObservableCollection<FundFlow> LoadFundFlows(FlowType flowType, DateTime dateFrom, DateTime dateTo);
        ObservableCollection<FundFlow> LoadFundFlows(DateTime dateFrom, DateTime dateTo);
        ObservableCollection<FundFlow> LoadFundFlows();
        ObservableCollection<FundFlow> LoadFundFlows(FlowType flowType);
        void Insert(FundFlow fundFlow);
        void Update(FundFlow fundFlow);
        bool ItemExistsInFundFlows(Item item);
        FundFlow GetById(int id);
        void Delete(int id);
    }

    public class FundFlowsRepository : IFundFlowsRepository
    {
        public ObservableCollection<FundFlow> LoadFundFlows(FlowType flowType, DateTime dateFrom, DateTime dateTo)
        {
            using (BalanceManagerDataContext db = new BalanceManagerDataContext(BalanceManagerDataContext.DBConnectionString))
            {
                var fundFlows = from ff in db.FundFlows
                    join item in db.Items on ff.ItemId equals item.Id
                    where ff.FlowType == flowType && ff.Date >= dateFrom && ff.Date <= dateTo
                    select new
                    {
                        Id = ff.Id,
                        Amount = ff.Amount,
                        Date = ff.Date,
                        FlowType = ff.FlowType,
                        ItemId = ff.ItemId,
                        ItemName = item.Name
                    };

                var fundFlowsList = new List<FundFlow>();
                foreach (var fundFlow in fundFlows)
                {
                    fundFlowsList.Add(new FundFlow
                    {
                        Id = fundFlow.Id,
                        Amount = fundFlow.Amount,
                        Date = fundFlow.Date,
                        FlowType = fundFlow.FlowType,
                        ItemId = fundFlow.ItemId,
                        ItemName = fundFlow.ItemName
                    });
                }

                return new ObservableCollection<FundFlow>(fundFlowsList);
            }
        }

        public ObservableCollection<FundFlow> LoadFundFlows(DateTime dateFrom, DateTime dateTo)
        {
            using (BalanceManagerDataContext db = new BalanceManagerDataContext(BalanceManagerDataContext.DBConnectionString))
            {
                var fundFlows = from ff in db.FundFlows
                                join item in db.Items on ff.ItemId equals item.Id
                                where ff.Date >= dateFrom && ff.Date <= dateTo
                                select new
                                {
                                    Id = ff.Id,
                                    Amount = ff.Amount,
                                    Date = ff.Date,
                                    FlowType = ff.FlowType,
                                    ItemId = ff.ItemId,
                                    ItemName = item.Name
                                };

                var fundFlowsList = new List<FundFlow>();
                foreach (var fundFlow in fundFlows)
                {
                    fundFlowsList.Add(new FundFlow
                    {
                        Id = fundFlow.Id,
                        Amount = fundFlow.Amount,
                        Date = fundFlow.Date,
                        FlowType = fundFlow.FlowType,
                        ItemId = fundFlow.ItemId,
                        ItemName = fundFlow.ItemName
                    });
                }

                return new ObservableCollection<FundFlow>(fundFlowsList);
            }
        }

        public ObservableCollection<FundFlow> LoadFundFlows()
        {
            var now = DateTime.Now;
            var dateFrom = new DateTime(now.Year, now.Month, now.Day, 0, 0, 0);
            var dateTo = new DateTime(now.Year, now.Month, now.Day, 23, 59, 59);
            return LoadFundFlows(dateFrom, dateTo);
        }

        public ObservableCollection<FundFlow> LoadFundFlows(FlowType flowType)
        {
            var now = DateTime.Now;
            var dateFrom = new DateTime(now.Year, now.Month, now.Day, 0, 0, 0);
            var dateTo = new DateTime(now.Year, now.Month, now.Day, 23, 59, 59);
            return LoadFundFlows(flowType, dateFrom, dateTo);
        }

        public void Insert(FundFlow fundFlow)
        {
            using (BalanceManagerDataContext db = new BalanceManagerDataContext(BalanceManagerDataContext.DBConnectionString))
            {
                db.FundFlows.InsertOnSubmit(fundFlow);
                db.SubmitChanges();
            }
        }

        public void Update(FundFlow fundFlow)
        {
            using (BalanceManagerDataContext db = new BalanceManagerDataContext(BalanceManagerDataContext.DBConnectionString))
            {
                var editable = db.FundFlows.First(o => o.Id == fundFlow.Id);
                editable.ItemId = fundFlow.ItemId;
                editable.Amount = fundFlow.Amount;
                editable.Date = fundFlow.Date;
                db.SubmitChanges();
            }
        }

        public bool ItemExistsInFundFlows(Item item)
        {
            using (BalanceManagerDataContext db = new BalanceManagerDataContext(BalanceManagerDataContext.DBConnectionString))
            {
                var findeditem = db.FundFlows.FirstOrDefault(ff => ff.ItemId == item.Id);
                return findeditem != null;
            }
        }

        public FundFlow GetById(int id)
        {
            using (BalanceManagerDataContext db = new BalanceManagerDataContext(BalanceManagerDataContext.DBConnectionString))
            {
                var findeditem = db.FundFlows.FirstOrDefault(ff => ff.Id == id);
                return findeditem;
            }
        }

        public void Delete(int id)
        {
            using (BalanceManagerDataContext db = new BalanceManagerDataContext(BalanceManagerDataContext.DBConnectionString))
            {
                var findeditem = db.FundFlows.FirstOrDefault(ff => ff.Id == id);
                db.FundFlows.DeleteOnSubmit(findeditem);
                db.SubmitChanges();
            }
        }

        public void InsertSampleData()
        {
            var items = new List<FundFlow>();
            for (var i = 0; i < 15; i++)
            {
                items.Add(new FundFlow
                {
                    Amount = i,
                    Date = DateTime.Now,
                    FlowType = i % 2 == 0 ? FlowType.Expense : FlowType.Profit,
                    ItemId = i
                });
            }

            using (BalanceManagerDataContext db = new BalanceManagerDataContext(BalanceManagerDataContext.DBConnectionString))
            {
                db.FundFlows.InsertAllOnSubmit(items);
                db.SubmitChanges();
            }
        }
    }
}
